import os
import re
import json
import webbrowser
import subprocess
import threading
import urllib.request
import winreg
import platform
import shutil
import zipfile
import tempfile
import tkinter as tk
from tkinter import filedialog
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
from pathlib import Path
import io
import email
import email.policy

# 配置常量
PORT = 65432
DATA_DIR = os.path.join(os.path.expanduser('~'), '.jcm')
CONFIG_FILE = os.path.join(DATA_DIR, 'config.json')
DOTNET_URL = "https://down.schub.top/down/9305"
DOTNET_FILENAME = "dotnet_installer.exe"
DEFAULT_INSTALL_PATH = os.path.join(os.path.expanduser('~'), 'Documents', 'SurvivalWarServer')

if not os.path.exists(DATA_DIR):
    os.makedirs(DATA_DIR)

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """处理并发请求"""

class CustomRequestHandler(BaseHTTPRequestHandler):
    def end_headers(self):
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate')
        super().end_headers()
    
    def do_GET(self):
        if self.path == '/':
            self.path = '/index.html'
            return self.serve_static()
        
        if self.path == '/check_dotnet':
            return self.handle_check_dotnet()
        
        if self.path == '/get_default_path':
            return self.handle_get_default_path()
        
        if self.path == '/open_folder':
            return self.handle_open_folder()
        
        if self.path == '/choose_install_path':
            return self.handle_choose_install_path()
        
        return self.serve_static()
    
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        
        if self.path == '/download_dotnet':
            return self.handle_download_dotnet()
        
        if self.path == '/install_server':
            return self.handle_install_server()
        
        self.send_error(404, "API Not Found")
    
    def serve_static(self):
        try:
            if self.path == '/':
                self.path = '/index.html'
            
            # 简化处理，实际中应使用更安全的静态文件服务
            with open('.' + self.path, 'rb') as file:
                self.send_response(200)
                self.send_header('Content-type', self.guess_mime_type(self.path))
                self.end_headers()
                self.wfile.write(file.read())
        except Exception as e:
            self.send_error(404, f"File not found: {str(e)}")
    
    def guess_mime_type(self, path):
        if path.endswith(".html"):
            return "text/html"
        if path.endswith(".css"):
            return "text/css"
        if path.endswith(".js"):
            return "application/javascript"
        return "text/plain"
    
    def handle_check_dotnet(self):
        """检查系统是否安装了.NET 4.7.2运行库"""
        try:
            # 获取Windows版本信息
            windows_version = platform.platform()
            system_arch = platform.architecture()[0]
            
            # 检查.NET Framework
            has_dotnet = False
            try:
                # 检查注册表
                key = winreg.OpenKey(
                    winreg.HKEY_LOCAL_MACHINE,
                    r"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full"
                )
                version, _ = winreg.QueryValueEx(key, "Version")
                winreg.CloseKey(key)
                
                # 检查版本是否 >= 4.7.2
                major, minor, build = map(int, version.split('.')[:3])
                if major >= 4 and minor >= 7 and build >= 2:
                    has_dotnet = True
            except Exception:
                pass
            
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            response = json.dumps({
                "status": "success",
                "has_dotnet": has_dotnet,
                "windows_version": windows_version,
                "system_arch": system_arch
            })
            self.wfile.write(response.encode('utf-8'))
        except Exception as e:
            self.send_response(500)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({
                "status": "error",
                "message": str(e)
            }).encode('utf-8'))
    
    def handle_download_dotnet(self):
        """下载.NET安装程序并实时报告进度"""
        try:
            self.send_response(200)
            self.send_header('Content-type', 'application/octet-stream')
            self.send_header('Content-Disposition', f'attachment; filename="{DOTNET_FILENAME}"')
            self.end_headers()
            
            # 创建下载路径
            download_path = os.path.join(os.path.expanduser('~'), 'Downloads', DOTNET_FILENAME)
            
            # 开始下载
            req = urllib.request.Request(DOTNET_URL)
            with urllib.request.urlopen(req) as response:
                file_size = int(response.info().get('Content-Length', 0))
                downloaded = 0
                chunk_size = 1024 * 128  # 128KB
                
                # 创建文件
                with open(download_path, 'wb') as out_file:
                    while True:
                        chunk = response.read(chunk_size)
                        if not chunk:
                            break
                        
                        downloaded += len(chunk)
                        out_file.write(chunk)
                        
                        # 发送进度数据
                        progress = min(int((downloaded / file_size) * 100), 100)
                        self.wfile.write(f"Progress: {progress}%\n".encode('utf-8'))
            
            # 下载完成
            self.wfile.write(b"Download complete")
        except Exception as e:
            self.send_response(500)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({
                "status": "error",
                "message": str(e)
            }).encode('utf-8'))
    
    def handle_install_server(self):
        """安装服务端程序"""
        try:
            # 获取内容类型
            content_type = self.headers.get('Content-Type', '')
            if not content_type.startswith('multipart/form-data'):
                raise ValueError("无效的请求格式")
            
            # 获取边界
            boundary = content_type.split("boundary=")[1].encode('utf-8')
            
            # 读取请求体
            content_length = int(self.headers['Content-Length'])
            body = self.rfile.read(content_length)
            
            # 解析multipart/form-data
            form_data = self.parse_multipart_form_data(body, boundary)
            
            # 获取安装路径
            install_path = form_data.get('path', DEFAULT_INSTALL_PATH)
            
            # 获取上传的文件
            file_item = form_data.get('file')
            if not file_item or not file_item['data']:
                raise ValueError("未提供有效的服务端文件")
            
            # 创建安装目录
            if not os.path.exists(install_path):
                os.makedirs(install_path)
            
            # 保存上传的文件到临时位置
            temp_file_path = os.path.join(tempfile.gettempdir(), file_item['filename'])
            with open(temp_file_path, 'wb') as f:
                f.write(file_item['data'])
            
            # 解压文件到安装目录
            print(f"正在解压服务端到: {install_path}")
            with zipfile.ZipFile(temp_file_path, 'r') as zip_ref:
                zip_ref.extractall(install_path)
            
            # 删除临时文件
            os.remove(temp_file_path)
            
            # 创建配置文件
            config = {
                "install_path": install_path,
                "version": "1.0",
                "dotnet_installed": True
            }
            
            with open(CONFIG_FILE, 'w') as f:
                json.dump(config, f, indent=2)
            
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({
                "status": "success",
                "message": "服务端安装完成",
                "install_path": install_path
            }).encode('utf-8'))
        except Exception as e:
            self.send_response(500)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({
                "status": "error",
                "message": str(e)
            }).encode('utf-8'))
    
    def parse_multipart_form_data(self, body, boundary):
        """解析multipart/form-data请求体"""
        form_data = {}
        
        # 添加前导边界
        boundary = b'--' + boundary
        
        # 分割部分
        parts = body.split(boundary)
        
        for part in parts:
            if not part or part == b'--\r\n':
                continue
                
            # 解析头部
            header_body = part.split(b'\r\n\r\n', 1)
            if len(header_body) < 2:
                continue
                
            headers = header_body[0]
            body = header_body[1].rstrip(b'\r\n')
            
            # 解析头部字段
            headers_dict = {}
            for line in headers.split(b'\r\n'):
                if b':' in line:
                    key, value = line.split(b':', 1)
                    headers_dict[key.strip().lower()] = value.strip()
            
            # 检查内容处置
            content_disposition = headers_dict.get(b'content-disposition', b'').decode('utf-8')
            if 'name="' not in content_disposition:
                continue
                
            # 提取字段名
            name_start = content_disposition.index('name="') + 6
            name_end = content_disposition.index('"', name_start)
            name = content_disposition[name_start:name_end]
            
            # 检查是否是文件
            if 'filename="' in content_disposition:
                filename_start = content_disposition.index('filename="') + 10
                filename_end = content_disposition.index('"', filename_start)
                filename = content_disposition[filename_start:filename_end]
                
                form_data[name] = {
                    'filename': filename,
                    'data': body
                }
            else:
                # 普通字段
                form_data[name] = body.decode('utf-8')
        
        return form_data
    
    def handle_get_default_path(self):
        """获取默认安装路径"""
        try:
            # 获取用户文档目录
            documents_path = os.path.join(os.path.expanduser('~'), 'Documents')
            default_path = os.path.join(documents_path, 'SurvivalWarServer')
            
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({
                "status": "success",
                "default_path": default_path
            }).encode('utf-8'))
        except Exception as e:
            self.send_response(500)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({
                "status": "error",
                "message": str(e)
            }).encode('utf-8'))
    
    def handle_open_folder(self):
        """打开服务端文件夹"""
        try:
            # 从配置文件中获取路径
            if os.path.exists(CONFIG_FILE):
                with open(CONFIG_FILE, 'r') as f:
                    config = json.load(f)
                    install_path = config.get('install_path', '')
                    
                    if install_path and os.path.exists(install_path):
                        # 打开文件夹
                        subprocess.Popen(f'explorer "{install_path}"', shell=True)
            
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({
                "status": "success",
                "path": install_path
            }).encode('utf-8'))
        except Exception as e:
            self.send_response(500)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({
                "status": "error",
                "message": str(e)
            }).encode('utf-8'))
    
    def handle_choose_install_path(self):
        """弹出文件夹选择对话框并返回选择的路径"""
        try:
            # 创建Tkinter根窗口并隐藏
            root = tk.Tk()
            root.withdraw()  # 隐藏主窗口
            root.attributes('-topmost', True)  # 确保对话框在最前面
            
            # 弹出文件夹选择对话框
            folder_path = filedialog.askdirectory(
                title="选择服务端安装路径",
                initialdir=os.path.expanduser('~')
            )
            
            # 销毁根窗口
            root.destroy()
            
            if folder_path:
                self.send_response(200)
                self.send_header('Content-type', 'application/json')
                self.end_headers()
                self.wfile.write(json.dumps({
                    "status": "success",
                    "path": folder_path
                }).encode('utf-8'))
            else:
                self.send_response(200)
                self.send_header('Content-type', 'application/json')
                self.end极速赛车开奖官网
                self.wfile.write(json.dumps({
                    "status": "cancel",
                    "message": "用户取消选择"
                }).encode('utf-8'))
        except Exception as e:
            self.send_response(500)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({
                "status": "error",
                "message": str(e)
            }).encode('utf-8'))

def run_server():
    """启动HTTP服务器"""
    if not os.path.exists('index.html'):
        print("错误: 当前目录下找不到 index.html 文件")
        return
    
    server_address = ('', PORT)
    httpd = ThreadedHTTPServer(server_address, CustomRequestHandler)
    
    print("=" * 50)
    print(f"🎉 服务器已启动! 在浏览器中打开: http://localhost:{PORT}")
    print("=" * 50)
    print("🛑 按 Ctrl+C 停止服务器")
    
    # 自动打开浏览器
    webbrowser.open(f"http://localhost:{PORT}")
    
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print("\n🛑 服务器已停止")
    finally:
        httpd.server_close()

if __name__ == '__main__':
    run_server()